﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace TapTapServer
{
    public class TrackManager : BackgroundWorker
    {
        enum difficulties { all = 0, easy = 1, medium = 2, hard = 3, extreme = 4 };
        Dictionary<difficulties, List<string>> templatesForDifficulty;


        Dictionary<difficulties, string> combinedTemplates;

        public TrackManager()
            : base()
        {
            WorkerReportsProgress = true;
            WorkerSupportsCancellation = true;
        }

        public void processDirectory(string containingFolder)
        {
            templatesForDifficulty = new Dictionary<difficulties, List<string>>();
            templatesForDifficulty.Add(difficulties.easy, new List<string>());
            templatesForDifficulty.Add(difficulties.medium, new List<string>());
            templatesForDifficulty.Add(difficulties.hard, new List<string>());
            templatesForDifficulty.Add(difficulties.extreme, new List<string>());
            templatesForDifficulty.Add(difficulties.all, new List<string>());
            combinedTemplates = new Dictionary<difficulties, string>();


            RunWorkerAsync(new workerArgs(containingFolder, true));

        }


        protected override void OnDoWork(DoWorkEventArgs e)
        {
            workerArgs args = (workerArgs)e.Argument;
            List<string> trackPaths = new List<string>();
            if (!args.isContainingFolder)
            {
                trackPaths.Add(args.folder);
            }
            else
            {
                trackPaths.AddRange(Directory.GetDirectories(args.folder));
            }

            string masterTemplate = File.ReadAllText(Path.Combine(Settings.Instance.ServerRootPath, "default.template"));
            masterTemplate = masterTemplate.Replace("[authenticated]", args.accountName);
            masterTemplate = masterTemplate.Replace("[authenticated_id]", args.accountID);

            combinedTemplates.Add(difficulties.easy, "");
            combinedTemplates.Add(difficulties.medium, "");
            combinedTemplates.Add(difficulties.hard, "");
            combinedTemplates.Add(difficulties.extreme, "");
            combinedTemplates.Add(difficulties.all, "");


            int count = 0;
            foreach (string pathToTrack in trackPaths)
            {
                if (!isValidTrack(pathToTrack))
                {//ask the user
                    if (MessageBox.Show("The track stored at \"" + pathToTrack + "\" appears to be either damaged or incomplete and will not play correctly. This track will be skipped. Do you want to process the remaining tracks?", "Invalid track detected", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false) == System.Windows.Forms.DialogResult.Yes)
                    {
                        continue;
                    }
                    else { CancelAsync(); break; }
                }

                StreamReader InfoReader = File.OpenText(Path.Combine(pathToTrack, "Info.plist"));
                string Info = InfoReader.ReadToEnd();
                InfoReader.Close();
                Info = Info.Substring(Info.IndexOf("<data>") + 6);
                Info = Info.Substring(0, Info.IndexOf("</data>"));
                Info = Info.Trim();
                Info = Info.Replace("\n\t", "");

                byte[] decoded = Convert.FromBase64String(Info);
                MemoryStream memStream = new MemoryStream(decoded.Length);
                memStream.Write(decoded, 0, decoded.Length);
                TrackInfo trackInfo = plistManager.readPlist(memStream);

                string trackTemplate = trackInfo.makeTemplate();
                templatesForDifficulty[difficulties.all].Add(trackTemplate);
                foreach (difficulties difficulty in trackInfo.availableDifficultyLevels)
                {
                    templatesForDifficulty[difficulty].Add(trackTemplate);
                }


                string savePath = Path.Combine(Settings.Instance.TracksPath, trackInfo.kTTRDownloadableItemUniqueIdentifierKey);


                copyFiles(pathToTrack, savePath);

                count++;
                float progress = ((float)count / (float)trackPaths.Count) * 100f;
                ReportProgress((int)progress, "Processed Track: " + trackInfo.kTTRDownloadableItemUniqueIdentifierKey);

                if (CancellationPending) break;
            }


            foreach (difficulties difficulty in templatesForDifficulty.Keys)
            {
                if (templatesForDifficulty[difficulty].Count == 1)
                {
                    combinedTemplates[difficulty] = "<key>song</key>";
                }
                else
                {
                    combinedTemplates[difficulty] = "<key>songs</key><array>";
                }

                foreach (string template in templatesForDifficulty[difficulty])
                {
                    combinedTemplates[difficulty] += template + "\n";
                }

                if (templatesForDifficulty[difficulty].Count != 1)
                {
                    combinedTemplates[difficulty] += "</array>";
                }
                File.WriteAllText(Path.Combine(Settings.Instance.ServerRootPath, @"tapplications\ttr\v3.0\" + difficulty.ToString() + "Tracks.plist"), masterTemplate.Replace("[songInfos]", combinedTemplates[difficulty]));
            }
        }

        bool isValidTrack(string pathToTrack)
        {
            if (File.Exists(Path.Combine(pathToTrack, "Info.plist")) && File.Exists(Path.Combine(pathToTrack, "audio.m4c")) || File.Exists(Path.Combine(pathToTrack, "audio.m4a")) && File.Exists(Path.Combine(pathToTrack, "\\taptrack.ttr2_track")))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        private void copyFiles(string sourceFolder, string destinationFolder)
        {
            if (!Directory.Exists(destinationFolder)) Directory.CreateDirectory(destinationFolder);
            foreach (string file in Directory.GetFiles(sourceFolder))
            {
                string destName = Path.Combine(destinationFolder, Path.GetFileName(file));

                File.Copy(file, destName, true);
            }
        }
    }
}
